package ybl.qianchuan;

import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.Map;

/**
 * Utility class for sending HTTP requests.
 */
public class HttpRequest {
    private static CloseableHttpClient client = HttpClients.createDefault();
    private static final ObjectMapper mapper = new ObjectMapper();

    /**
     * Send a POST request.
     *
     * @param url        URL to send the request to.
     * @param params     Parameters to include in the request body.
     * @param accessToken Access token for authorization, if required.
     * @return JSONObject representing the response.
     */
    public static JSONObject post(String url, Map<String, Object> params, String accessToken) {
        return sendRequest(new HttpPost(url), params, accessToken);
    }

    /**
     * Overloaded method to send a POST request without an access token.
     *
     * @param url    URL to send the request to.
     * @param params Parameters to include in the request body.
     * @return JSONObject representing the response.
     */
    public static JSONObject post(String url, Map<String, Object> params) {
        return post(url, params, null);
    }

    /**
     * Send a GET request.
     *
     * @param url        URL to send the request to.
     * @param params     Parameters to include in the request URL.
     * @param accessToken Access token for authorization, if required.
     * @return JSONObject representing the response.
     */
    public static JSONObject get(String url, Map<String, Object> params, String accessToken) {
        try {
            URIBuilder ub = new URIBuilder(url);
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                ub.addParameter(key, value instanceof String ? (String) value : mapper.writeValueAsString(value));
            }
            HttpGet request = new HttpGet(ub.build());
            if (accessToken != null) {
                request.setHeader("Access-Token", accessToken);
            }
            try (CloseableHttpResponse response = client.execute(request)) {
                String responseString = EntityUtils.toString(response.getEntity());
                return JSONObject.parseObject(responseString);
            }
        } catch (URISyntaxException | JsonProcessingException e) {
            handleException(e);
        } catch (IOException e) {
            handleException(e);
        }
        return null;
    }

    /**
     * Overloaded method to send a GET request without an access token.
     *
     * @param url    URL to send the request to.
     * @param params Parameters to include in the request URL.
     * @return JSONObject representing the response.
     */
    public static JSONObject get(String url, Map<String, Object> params) {
        return get(url, params, null);
    }

    /**
     * Sends a request using the given HttpEntityEnclosingRequestBase (can be used for both GET and POST).
     *
     * @param request     HttpEntityEnclosingRequestBase object representing the request.
     * @param params      Parameters to include in the request.
     * @param accessToken Access token for authorization, if required.
     * @return JSONObject representing the response.
     */
    private static JSONObject sendRequest(HttpEntityEnclosingRequestBase request, Map<String, Object> params, String accessToken) {
        try {
            if (accessToken != null) {
                request.setHeader("Access-Token", accessToken);
            }
            request.setEntity(new StringEntity(JSONObject.toJSONString(params), ContentType.APPLICATION_JSON));

            try (CloseableHttpResponse response = client.execute(request);
                 BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {

                StringBuilder result = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }
                return JSONObject.parseObject(result.toString());
            }
        } catch (ClientProtocolException e) {
            handleException(e);
        } catch (IOException e) {
            handleException(e);
        }
        return null;
    }

    /**
     * Handles exceptions that may occur during the request.
     *
     * @param e Exception to handle.
     */
    private static void handleException(Exception e) {
        // Unified exception handling
        e.printStackTrace();
        // Add more error handling logic as needed, such as logging or returning error information
    }
}
